{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f71ca602",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sqlalchemy import create_engine\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import tushare as ts\n",
    "from datetime import datetime\n",
    "from datetime import timedelta\n",
    "from tqdm.notebook import tqdm\n",
    "import statsmodels.api as sm\n",
    "from statsmodels.regression.rolling import RollingOLS\n",
    "from utils import get_codes,get_index_close,get_data_by_sql,get_pivot_data,halflife_weighting\n",
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "1e5eae63",
   "metadata": {},
   "outputs": [],
   "source": [
    "start_time = time.time()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9b946e3e",
   "metadata": {},
   "outputs": [],
   "source": [
    "folder_path = 'data/'\n",
    "file_path = f'sqlite:////{folder_path}'\n",
    "\n",
    "token = 'd942e6ff0e981f76aaa544f84405583e0c2129a8c82213637835a099'\n",
    "pro = ts.pro_api(token)\n",
    "\n",
    "start_date = '20100101'\n",
    "index_code = '000001.SH'\n",
    "today = datetime.strftime(datetime.now(),'%Y%m%d')\n",
    "df_index = get_index_close(index_code=index_code,start_date=start_date)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b627dbd",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71732ced",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6e53221d",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "03068db2",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c7a8decd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 按全市场条件筛选获取股票篮子\n",
    "df_stocks = pro.stock_basic()\n",
    "df_stocks = df_stocks[df_stocks['list_date']<'20200101']\n",
    "df_stocks = df_stocks[df_stocks['market']=='主板']\n",
    "codes = list(df_stocks['ts_code'])\n",
    "\n",
    "# 按指数成分股获取股票篮子\n",
    "# codes = get_codes(index_code=index_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "73667825",
   "metadata": {},
   "outputs": [],
   "source": [
    "calendar = pro.trade_cal(exchange='SSE', start_date=start_date,end_date=today)\n",
    "calendar = calendar[calendar['is_open']==1]\n",
    "calendar.index = pd.to_datetime(calendar['cal_date'])\n",
    "calendar = calendar.index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1ea09a18",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_shibor = pro.shibor(start_date=start_date)\n",
    "df_shibor.index = pd.to_datetime(df_shibor['date'])\n",
    "df_riskfree = df_shibor['1m']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "d75661f4",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "df_adj = get_data_by_sql(file_path,'daily_adj','daily_adj',codes)\n",
    "df_kline = get_data_by_sql(file_path,'daily_kline','daily_kline',codes)\n",
    "df_basic = get_data_by_sql(file_path,'dailybasic','dailybasic',codes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "96595293",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ffa8c3f1",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 合成后复权的收盘价数据\n",
    "df_adj = get_pivot_data(df_adj,'adj_factor')\n",
    "df_close = get_pivot_data(df_kline,'close')\n",
    "df_close = (df_close*df_adj/df_adj.loc[df_adj.index[-1]]).round(2)\n",
    "\n",
    "df_total_mv = get_pivot_data(df_basic,'total_mv')\n",
    "df_pb = get_pivot_data(df_basic,'pb')\n",
    "\n",
    "# 这两个因子可直接对df操作生成\n",
    "SIZE = np.log(df_total_mv)\n",
    "BP = 1/df_pb "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d3d5ddb",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "28b052ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_index = df_index[df_index.index<=df_close.index[-1]]\n",
    "close_ret = np.log(df_close).diff()\n",
    "index_ret = np.log(df_index['close']).diff()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "0fdeb2ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "# factor_folder = 'factors/'\n",
    "\n",
    "# close_ret.to_csv(factor_folder+'close_ret.csv')\n",
    "# index_ret.to_csv(factor_folder+'index_ret.csv')\n",
    "\n",
    "# SIZE.to_csv(factor_folder+'SIZE.csv')\n",
    "# BP.to_csv(factor_folder+'BP.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b36b5e4",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47829bec",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4d8b8ba",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "425fc721",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "3b41d714e2564b119f782a2eaeda6e72",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1933 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def get_non_linear_size(code):\n",
    "    y = (np.log(df_total_mv)**3)[code]\n",
    "    X = np.log(df_total_mv)[code]\n",
    "    X = sm.add_constant(X)\n",
    "    \n",
    "    # 因子说明中，没有说是滚动的，但我个人倾向于用滚动，避免回测的时候有偷看未来之嫌\n",
    "    model = RollingOLS(endog=y,\n",
    "                       exog=X,\n",
    "                       window=252*2,\n",
    "                       expanding=True,\n",
    "                       min_nobs=42)\n",
    "\n",
    "    res = model.fit()\n",
    "    non_linear_size = y - (res.params * X).sum(1)\n",
    "    return non_linear_size\n",
    "\n",
    "dds = []\n",
    "for code in tqdm(codes):\n",
    "    dds.append(get_non_linear_size(code))\n",
    "    \n",
    "NonLinerSize = pd.concat(dds,axis=1)\n",
    "NonLinerSize.columns = codes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15159a46",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e00440a5",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "998a1bc2",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "ac7901ff6bb44a64a1a1d484b9a83545",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1933 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def get_beta_and_hsigma(code,index_ret):\n",
    "    \"\"\"\n",
    "    计算BETA和HSIGMA\n",
    "    \"\"\"\n",
    "    halflife = 63\n",
    "    index_ewm_ret = halflife_weighting(index_ret,halflife)\n",
    "    index_ewm_ret = sm.add_constant(index_ewm_ret)\n",
    "\n",
    "    stock = close_ret[code]\n",
    "    model = RollingOLS(endog=stock,\n",
    "                       exog=index_ewm_ret,\n",
    "                       window=252,\n",
    "                       expanding=True,\n",
    "                       min_nobs=42)\n",
    "\n",
    "    res = model.fit()\n",
    "    beta = res.params['close']\n",
    "    # 由于残差的均值为0，因此barra因子描述中的残差的标准差等价于残差的平方和除以自由度（或者差不多也是观察值数量）\n",
    "    # 而根据RollingOLS的接口说明可以得知mse_resid正好就是我们需要的标准差\n",
    "    hsigma = res.mse_resid\n",
    "    return beta,hsigma\n",
    "\n",
    "dds1 = []\n",
    "dds2 = []\n",
    "for code in tqdm(codes):\n",
    "    beta,hsigma = get_beta_and_hsigma(code,index_ret)\n",
    "    dds1.append(beta)\n",
    "    dds2.append(hsigma)\n",
    "    \n",
    "BETA = pd.concat(dds1,axis=1)\n",
    "BETA.columns = codes\n",
    "\n",
    "HSIGMA = pd.concat(dds2,axis=1)\n",
    "HSIGMA.columns = codes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "84326d80",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "99b9e623",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "97042d4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_float_share = get_pivot_data(df_basic,'float_share')\n",
    "df_vol = get_pivot_data(df_kline,'vol')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "d4ffbd84",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 下面两个获得换手率的方法等价\n",
    "# df_turnover_rate = get_pivot_data(df_basic,'turnover_rate')\n",
    "df_float_share = get_pivot_data(df_basic,'float_share')\n",
    "df_vol = get_pivot_data(df_kline,'vol')\n",
    "df_turnover_rate = df_vol/df_float_share\n",
    "STOM = np.log(df_turnover_rate.rolling(21).mean())\n",
    "STOQ = np.log(df_turnover_rate.rolling(63).mean())\n",
    "STOA = np.log(df_turnover_rate.rolling(252).mean())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "072342eb",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "RSTR = halflife_weighting(close_ret,126).rolling(504-21).sum().shift(21)\n",
    "# 本来想用shibor作为无风险利率，发现时间段最早只有13年，暂时找不到其他时间足够长且接口可随时调取的利率数据\n",
    "# 因此下面计算DASTD时个股收益率没有减去无风险利率\n",
    "DASTD = halflife_weighting(close_ret**2,42).rolling(252).sum()**0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "03c6f754",
   "metadata": {},
   "outputs": [],
   "source": [
    "ZT = np.exp(close_ret.rolling(252).sum()) - 1\n",
    "CMRA = np.log(1 + ZT.rolling(252).max()) - np.log(1 + ZT.rolling(252).min())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "aa1f1be7",
   "metadata": {},
   "outputs": [],
   "source": [
    "CETOP = 1/get_pivot_data(df_basic,'ps_ttm')\n",
    "ETOP = 1/get_pivot_data(df_basic,'pe_ttm')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "12dd39f7",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "df_income = get_data_by_sql(file_path,'financial_data','利润表',codes)\n",
    "df_income = df_income[df_income['report_type']=='2']\n",
    "df_income = df_income[df_income['end_date']>=start_date]\n",
    "df_income = df_income.sort_values(by=['ts_code','end_date']).reset_index(drop=True)\n",
    "df_income = df_income.drop_duplicates(subset=['ts_code','end_date'],keep='last').reset_index(drop=True)\n",
    "df_income = df_income.reset_index(drop=True)\n",
    "df_income['f_ann_date'] = pd.to_datetime(df_income['f_ann_date'])\n",
    "# 利润表用0填充缺失值\n",
    "df_income = df_income.fillna(0)\n",
    "\n",
    "df_balance = get_data_by_sql(file_path,'financial_data','资产负债表',codes)\n",
    "df_balance = df_balance[df_balance['end_date']>=start_date]\n",
    "df_balance = df_balance.sort_values(by=['ts_code','end_date']).reset_index(drop=True)\n",
    "df_balance = df_balance.drop_duplicates(subset=['ts_code','end_date'],keep='last')\n",
    "df_balance = df_balance.reset_index(drop=True)\n",
    "df_balance['f_ann_date'] = pd.to_datetime(df_balance['f_ann_date'])\n",
    "# 资产负债表用前值填充缺失值\n",
    "df_balance = df_balance.fillna(method='ffill')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "0d838074",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 这里净利润采用“净利润(不含少数股东损益)”，而不是“净利润(含少数股东损益)”\n",
    "# 这里的营业收入采用“营业收入”，而不是“营业总收入”\n",
    "df_income[['n_income_yoy','revenue_yoy']] = df_income[['ts_code','n_income_attr_p','revenue']]\\\n",
    ".groupby(['ts_code']).apply(lambda x:x/x.shift(4) - 1)\n",
    "\n",
    "# 这里默认三张财务表发布日期都是一样的日期，因此只需取一个公布日期数据即可，后续重复利用\n",
    "# 也就是说下面的df_income，也可以换成df_balance\n",
    "df_ann_dates = get_pivot_data(df_income,'f_ann_date')\n",
    "\n",
    "# 准备财务数据的df,每个df的index是财报日end_date，columns是股票代码\n",
    "df_income_yoy = get_pivot_data(df_income,'n_income_yoy')\n",
    "df_revenue_yoy = get_pivot_data(df_income,'revenue_yoy')\n",
    "df_balance['book_leverage'] = (df_balance['total_hldr_eqy_inc_min_int'] + \\\n",
    "                               df_balance['lt_payable'] + \\\n",
    "                               df_balance['lt_borr'])/ \\\n",
    "                               df_balance['total_hldr_eqy_inc_min_int']\n",
    "df_balance['asset_liability_ratio'] = df_balance['total_assets']/df_balance['total_liab']\n",
    "df_total_ncl = get_pivot_data(df_balance,'total_ncl')\n",
    "df_asset_liability_ratio = get_pivot_data(df_balance,'asset_liability_ratio')\n",
    "df_book_leverage = get_pivot_data(df_balance,'book_leverage')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "f744def5",
   "metadata": {},
   "outputs": [],
   "source": [
    "list_df_vals = [df_income_yoy,df_revenue_yoy,\n",
    "                df_total_ncl,df_asset_liability_ratio,\n",
    "                df_book_leverage]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "36b7d218",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "9b51650c14ae4ee3a0500328afe586fb",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1933 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ppp = []\n",
    "for code in tqdm(codes):\n",
    "    pp = []\n",
    "    vals = [np.nan]*len(list_df_vals)\n",
    "    for date in calendar:\n",
    "        for end_date in df_ann_dates.index[::-1]:\n",
    "            if date > df_ann_dates.loc[end_date,code]:\n",
    "                vals = [dd_vals.loc[end_date,code] for dd_vals in list_df_vals]\n",
    "                break\n",
    "        pp.append(vals)\n",
    "    ppp.append(pp)\n",
    "    \n",
    "ppp = np.swapaxes(np.array(ppp),0,1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d2756f2",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8090a316",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "98530ed9",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "YOYProfit,YOYSales,ncl,DTOA,BLEV = \\\n",
    "[pd.DataFrame(ppp[:,:,i],index=calendar,columns=codes) for i in range(len(list_df_vals))]\n",
    "\n",
    "MLEV = 1 + ncl/df_total_mv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "6c49e01a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "11144.228113174438"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time.time()-start_time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "739aa5f6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>000001.SZ</th>\n",
       "      <th>000002.SZ</th>\n",
       "      <th>000004.SZ</th>\n",
       "      <th>000005.SZ</th>\n",
       "      <th>000006.SZ</th>\n",
       "      <th>000007.SZ</th>\n",
       "      <th>000008.SZ</th>\n",
       "      <th>000009.SZ</th>\n",
       "      <th>000010.SZ</th>\n",
       "      <th>000011.SZ</th>\n",
       "      <th>...</th>\n",
       "      <th>603989.SH</th>\n",
       "      <th>603990.SH</th>\n",
       "      <th>603991.SH</th>\n",
       "      <th>603992.SH</th>\n",
       "      <th>603993.SH</th>\n",
       "      <th>603995.SH</th>\n",
       "      <th>603996.SH</th>\n",
       "      <th>603997.SH</th>\n",
       "      <th>603998.SH</th>\n",
       "      <th>603999.SH</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>cal_date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2010-01-04</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-05</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-06</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-07</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-08</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-08</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.020124</td>\n",
       "      <td>1.006648</td>\n",
       "      <td>1.520771</td>\n",
       "      <td>1.087763</td>\n",
       "      <td>1.087287</td>\n",
       "      <td>1.174092</td>\n",
       "      <td>1.16039</td>\n",
       "      <td>1.825084</td>\n",
       "      <td>...</td>\n",
       "      <td>1.016177</td>\n",
       "      <td>1.048284</td>\n",
       "      <td>1.212045</td>\n",
       "      <td>1.032395</td>\n",
       "      <td>1.285081</td>\n",
       "      <td>1.246187</td>\n",
       "      <td>0.595105</td>\n",
       "      <td>1.434476</td>\n",
       "      <td>1.03151</td>\n",
       "      <td>1.041293</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-09</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.020124</td>\n",
       "      <td>1.006648</td>\n",
       "      <td>1.520771</td>\n",
       "      <td>1.087763</td>\n",
       "      <td>1.087287</td>\n",
       "      <td>1.174092</td>\n",
       "      <td>1.16039</td>\n",
       "      <td>1.825084</td>\n",
       "      <td>...</td>\n",
       "      <td>1.016177</td>\n",
       "      <td>1.048284</td>\n",
       "      <td>1.212045</td>\n",
       "      <td>1.032395</td>\n",
       "      <td>1.285081</td>\n",
       "      <td>1.246187</td>\n",
       "      <td>0.595105</td>\n",
       "      <td>1.434476</td>\n",
       "      <td>1.03151</td>\n",
       "      <td>1.041293</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-10</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.020124</td>\n",
       "      <td>1.006648</td>\n",
       "      <td>1.520771</td>\n",
       "      <td>1.087763</td>\n",
       "      <td>1.087287</td>\n",
       "      <td>1.174092</td>\n",
       "      <td>1.16039</td>\n",
       "      <td>1.825084</td>\n",
       "      <td>...</td>\n",
       "      <td>1.016177</td>\n",
       "      <td>1.048284</td>\n",
       "      <td>1.212045</td>\n",
       "      <td>1.032395</td>\n",
       "      <td>1.285081</td>\n",
       "      <td>1.246187</td>\n",
       "      <td>0.595105</td>\n",
       "      <td>1.434476</td>\n",
       "      <td>1.03151</td>\n",
       "      <td>1.041293</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-11</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.020124</td>\n",
       "      <td>1.006648</td>\n",
       "      <td>1.520771</td>\n",
       "      <td>1.087763</td>\n",
       "      <td>1.087287</td>\n",
       "      <td>1.174092</td>\n",
       "      <td>1.16039</td>\n",
       "      <td>1.825084</td>\n",
       "      <td>...</td>\n",
       "      <td>1.016177</td>\n",
       "      <td>1.048284</td>\n",
       "      <td>1.212045</td>\n",
       "      <td>1.032395</td>\n",
       "      <td>1.285081</td>\n",
       "      <td>1.246187</td>\n",
       "      <td>0.595105</td>\n",
       "      <td>1.434476</td>\n",
       "      <td>1.03151</td>\n",
       "      <td>1.041293</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-11-12</th>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>1.020124</td>\n",
       "      <td>1.006648</td>\n",
       "      <td>1.520771</td>\n",
       "      <td>1.087763</td>\n",
       "      <td>1.087287</td>\n",
       "      <td>1.174092</td>\n",
       "      <td>1.16039</td>\n",
       "      <td>1.825084</td>\n",
       "      <td>...</td>\n",
       "      <td>1.016177</td>\n",
       "      <td>1.048284</td>\n",
       "      <td>1.212045</td>\n",
       "      <td>1.032395</td>\n",
       "      <td>1.285081</td>\n",
       "      <td>1.246187</td>\n",
       "      <td>0.595105</td>\n",
       "      <td>1.434476</td>\n",
       "      <td>1.03151</td>\n",
       "      <td>1.041293</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>2882 rows × 1933 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            000001.SZ  000002.SZ  000004.SZ  000005.SZ  000006.SZ  000007.SZ  \\\n",
       "cal_date                                                                       \n",
       "2010-01-04        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-05        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-06        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-07        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-08        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "...               ...        ...        ...        ...        ...        ...   \n",
       "2021-11-08        NaN        NaN   1.020124   1.006648   1.520771   1.087763   \n",
       "2021-11-09        NaN        NaN   1.020124   1.006648   1.520771   1.087763   \n",
       "2021-11-10        NaN        NaN   1.020124   1.006648   1.520771   1.087763   \n",
       "2021-11-11        NaN        NaN   1.020124   1.006648   1.520771   1.087763   \n",
       "2021-11-12        NaN        NaN   1.020124   1.006648   1.520771   1.087763   \n",
       "\n",
       "            000008.SZ  000009.SZ  000010.SZ  000011.SZ  ...  603989.SH  \\\n",
       "cal_date                                                ...              \n",
       "2010-01-04        NaN        NaN        NaN        NaN  ...        NaN   \n",
       "2010-01-05        NaN        NaN        NaN        NaN  ...        NaN   \n",
       "2010-01-06        NaN        NaN        NaN        NaN  ...        NaN   \n",
       "2010-01-07        NaN        NaN        NaN        NaN  ...        NaN   \n",
       "2010-01-08        NaN        NaN        NaN        NaN  ...        NaN   \n",
       "...               ...        ...        ...        ...  ...        ...   \n",
       "2021-11-08   1.087287   1.174092    1.16039   1.825084  ...   1.016177   \n",
       "2021-11-09   1.087287   1.174092    1.16039   1.825084  ...   1.016177   \n",
       "2021-11-10   1.087287   1.174092    1.16039   1.825084  ...   1.016177   \n",
       "2021-11-11   1.087287   1.174092    1.16039   1.825084  ...   1.016177   \n",
       "2021-11-12   1.087287   1.174092    1.16039   1.825084  ...   1.016177   \n",
       "\n",
       "            603990.SH  603991.SH  603992.SH  603993.SH  603995.SH  603996.SH  \\\n",
       "cal_date                                                                       \n",
       "2010-01-04        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-05        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-06        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-07        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "2010-01-08        NaN        NaN        NaN        NaN        NaN        NaN   \n",
       "...               ...        ...        ...        ...        ...        ...   \n",
       "2021-11-08   1.048284   1.212045   1.032395   1.285081   1.246187   0.595105   \n",
       "2021-11-09   1.048284   1.212045   1.032395   1.285081   1.246187   0.595105   \n",
       "2021-11-10   1.048284   1.212045   1.032395   1.285081   1.246187   0.595105   \n",
       "2021-11-11   1.048284   1.212045   1.032395   1.285081   1.246187   0.595105   \n",
       "2021-11-12   1.048284   1.212045   1.032395   1.285081   1.246187   0.595105   \n",
       "\n",
       "            603997.SH  603998.SH  603999.SH  \n",
       "cal_date                                     \n",
       "2010-01-04        NaN        NaN        NaN  \n",
       "2010-01-05        NaN        NaN        NaN  \n",
       "2010-01-06        NaN        NaN        NaN  \n",
       "2010-01-07        NaN        NaN        NaN  \n",
       "2010-01-08        NaN        NaN        NaN  \n",
       "...               ...        ...        ...  \n",
       "2021-11-08   1.434476    1.03151   1.041293  \n",
       "2021-11-09   1.434476    1.03151   1.041293  \n",
       "2021-11-10   1.434476    1.03151   1.041293  \n",
       "2021-11-11   1.434476    1.03151   1.041293  \n",
       "2021-11-12   1.434476    1.03151   1.041293  \n",
       "\n",
       "[2882 rows x 1933 columns]"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "factors = [SIZE,BP,NonLinerSize,BETA,HSIGMA,STOM,STOQ,STOA,RSTR,DASTD,CMRA,CETOP,ETOP,YOYProfit,YOYSales,MLEV,DTOA,BLEV]\n",
    "for factor in factors:\n",
    "    factor.to_csv('factors/')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "ab3fc1d5",
   "metadata": {},
   "outputs": [],
   "source": [
    "names = \"SIZE,BP,NonLinerSize,BETA,HSIGMA,STOM,STOQ,STOA,RSTR,DASTD,CMRA,CETOP,ETOP,YOYProfit,YOYSales,MLEV,DTOA,BLEV\".split(',')\n",
    "factors = [SIZE,BP,NonLinerSize,BETA,HSIGMA,STOM,STOQ,STOA,RSTR,DASTD,CMRA,CETOP,ETOP,YOYProfit,YOYSales,MLEV,DTOA,BLEV]\n",
    "factors_dict = dict(zip(names,factors))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "d1df7d06",
   "metadata": {},
   "outputs": [],
   "source": [
    "for key in factors_dict.keys():\n",
    "    factors_dict[key].to_csv(f'factors/{key}.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50e8507d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
